<?php

declare(strict_types=1);

namespace App\Service;

use App\Event\UserCreated;
use App\Exception\BusinessException;
use App\Lib\BaseValidator;
use App\Lib\ValidateException;
use App\Repository\User\UserProfilesRepository;
use Hyperf\Di\Annotation\Inject;
use App\Repository\User\UserRepository;
use Psr\EventDispatcher\EventDispatcherInterface;

class UserService
{
    #[Inject]
    protected UserRepository $userRepository;

    #[Inject]
    protected EventDispatcherInterface $eventDispatcher;

    #[Inject]
    protected UserProfilesRepository $userProfilesRepository;

    /**
     * 注册用户
     * @param array $data
     * @return array
     */
    public function createUser(array $data): array
    {
        // 数据验证
        $this->validateUserData($data);

        // 业务逻辑处理
        $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
        $data['email_verified_at'] = null;

        //此处注册user用户
        $data['role'] = 'user';

        // 创建用户
        $user = $this->userRepository->create($data);

        // 触发用户创建事件
        $this->eventDispatcher->dispatch(new UserCreated($user));

        $token = $this->generateToken($user);
        return ["user" => $user, "token" => $token];
    }

    /**
     * 用户登录
     * @param string $email
     * @param string $password
     * @param string $ip
     * @param string $role
     * @return array
     */
    public function login(string $email, string $password, string $ip, string $role = "user"): array
    {
        // 根据邮箱查询用户信息
        $user = $this->userRepository->findByEmail($email);

        // 验证邮箱和密码是否正确
        if (!$user || !password_verify($password, $user['password'])) {
            throw new BusinessException('邮箱或密码错误');
        }

        // 验证角色
        if($user['role'] != $role){
            throw new BusinessException('角色异常');
        }

        // 验证账号状态
        if ($user['status'] !== 'active') {
            throw new BusinessException('账号已被禁用');
        }

        // 生成接口访问 token
        $token = $this->generateToken($user);

        // 更新登录信息
        $this->userRepository->updateLoginInfo($user['id'], $ip);

        // 去掉敏感信息
        unset($user['password']);

        return [
            'user' => $user,
            'token' => $token,
            'expires_in' => 7200
        ];
    }

    private function validateUserData(array $data): void
    {
        $validator_result = BaseValidator::make($data, [
            'name' => 'required|string|min:2|max:20|unique:users',
            'email' => 'required|email|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ], [
            'name.required' => '用户名不能为空！',
            'name.min' => '用户名长度需为2-20字符！',
            'name.max' => '用户名长度需为2-20字符！',
            'email.required' => '邮箱不能为空！',
            'name.unique' => '用户名已被占用！',
            'email.email' => '邮箱格式有误！',
            'email.unique' => '邮箱已被占用！',
            'password.required' => '密码不能为空',
            'password.min' => '密码最低8个字符',
            'password.confirmed' => '密码两次输入不一致'
        ]);
        if (!$validator_result) {
            throw new BusinessException(\App\Lib\BaseValidator::$error, 0);
        }
    }

    /**
     * 生成token
     * @param array $user
     * @return string
     */
    private function generateToken(array $user): string
    {
        return base64_encode(json_encode(['acl' => [
            'user_id' => $user['id'],
            'email' => $user['email'],
            'role' => $user['role'],
        ]]));
    }

    /**
     * 根据用户id获取用户信息
     * @param string $id
     * @param bool $withProfiles
     * @return mixed
     */
    public function getUserById(string $id, bool $withProfiles = false): array
    {
        $user = $this->userRepository->getDataById($id);
        if (!$user) {
            throw new BusinessException('无此用户');
        }
        //需要连带资料
        if ($withProfiles) {
            $user['profile'] = $this->userProfilesRepository->getDataById((string)$user['id']);
        }
        return $user;
    }

    /**
     * 跟新用户信息
     * @param array $data
     * @param string $id
     * @return void
     */
    public function updateUser(array $data, string $id): void
    {
        // 获取用户信息
        $user = $this->getUserById($id, true);

        //名字相同不更新
        if ($user['name'] == $data['name']) {
            unset($data['name']);
        }

        // 数据验证
        try {
            BaseValidator::make($data, [
                'name' => 'string|min:2|max:20|unique:users',
                'avatar' => 'url',
            ], [
                'name.required' => '用户名不能为空！',
                'name.unique' => '用户名被占用',
                'name.min' => '用户名长度需为2-20字符！',
                'name.max' => '用户名长度需为2-20字符！',
                'avatar.url' => '头像格式有误！'
            ]);
        } catch (ValidateException $e) {
            throw new BusinessException(BaseValidator::$error, 0);
        }

        $this->userRepository->updateNameAndAvatar($data, $id, $user);
    }

}